package org.pearl.springbootsecurity.demo.MP.data;

import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.StrUtil;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by TD on 2021/11/3
 * 数据权限处理器抽象类
 */
public abstract class AbstractDataScopeHandler implements IDataScopeHandler {

    /**
     * 默认部门字段名称
     */
    public String defaultDeptFiled;

    /**
     * 所有字段关键字
     */
    public static final String ALL_COLUMN_FILED = "*";

    /**
     * 获取 ItemsList，由子类实现
     *
     * @return ItemsList IN 表达式元素集合
     */
    abstract ItemsList renderInExpressionList();

    /**
     * 获取动态的数据权限，由子类实现
     *
     * @param msId MappedStatementID
     * @return DynamicDataPermission 动态的数据权限
     */
    abstract DynamicDataPermission renderDataPermission(Object msId);

    @Override
    public void buildInExpression(PlainSelect plainSelect, DataScopeMapperProperty dataScopeProperty) {
        // 1. 构建In 表达式
        FromItem fromItem = plainSelect.getFromItem();
        if (fromItem instanceof Table) {
            Column aliasColumn = getAliasColumn((Table) fromItem, defaultDeptFiled);
            InExpression inExpression = new InExpression(aliasColumn, renderInExpressionList());
            // 2. 添加新的Where语句
            if (null == plainSelect.getWhere()) {
                plainSelect.setWhere(new Parenthesis(inExpression));
            } else {
                plainSelect.setWhere(new AndExpression(plainSelect.getWhere(), inExpression));
            }
        }
    }

    @Override
    public void buildDynamicExpression(PlainSelect plainSelect, Object msId) throws JSQLParserException {
        // 1. 子类查询动态数据权限
        DynamicDataPermission dynamicDataPermission = renderDataPermission(msId);
        String dataPermissionSql = dynamicDataPermission.getExpression();// 数据库中的SQL表表示
        // 2.  处理查询字段
        String fields = dynamicDataPermission.getSelectItems();
        if (StrUtil.isNotEmpty(fields)) { // 配置了查询哪些字段
            List<SelectItem> selectItems = new ArrayList<>();
            if (ALL_COLUMN_FILED.equals(fields)) { // 所有字段
                selectItems.add(new AllColumns());
            } else {
                String[] fieldArray = fields.split(StrPool.COMMA);
                for (String field : fieldArray) {
                    SelectExpressionItem selectExpressionItem = new SelectExpressionItem();
                    selectExpressionItem.setExpression(new Column(field));
                    selectItems.add(selectExpressionItem);
                }
                plainSelect.setSelectItems(selectItems);
            }
        }
        // 2. 添加查询条件
        Expression expression = CCJSqlParserUtil.parseCondExpression(dataPermissionSql);
        Expression where = plainSelect.getWhere();
        if (where == null) {
            plainSelect.setWhere(expression);
        } else {
            plainSelect.setWhere(where instanceof OrExpression ? new AndExpression(new Parenthesis(where), expression) : new AndExpression(where, expression));
        }
    }

    /**
     * 获取带别名的列
     *
     * @param table      表
     * @param columnName 列名
     * @return 新的列名
     */
    public Column getAliasColumn(Table table, String columnName) {
        StringBuilder column = new StringBuilder();
        if (table.getAlias() != null) {
            column.append(table.getAlias().getName()).append(".");
        }
        column.append(columnName);
        return new Column(column.toString());
    }

    /**
     * 构建 = 表达式
     *
     * @param plainSelect 普通查询对象
     * @param column      列名
     * @param value       值
     */
    protected void buildEqualToExpression(PlainSelect plainSelect, String column, Expression value) {
        // 1. 构建等于表达式
        FromItem fromItem = plainSelect.getFromItem();
        Column aliasColumn = getAliasColumn((Table) fromItem, column);
        Expression where = plainSelect.getWhere();
        EqualsTo equalsToExpression = new EqualsTo();
        equalsToExpression.setLeftExpression(aliasColumn);
        equalsToExpression.setRightExpression(value);
        // 2. 添加表达式
        if (where == null) {
            plainSelect.setWhere(equalsToExpression);
        } else {
            plainSelect.setWhere(where instanceof OrExpression ? new AndExpression(new Parenthesis(where), equalsToExpression) : new AndExpression(where, equalsToExpression));
        }
    }
}
